home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tcl8.0 / mac / tclMacAlloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  8.2 KB  |  341 lines  |  [TEXT/CWIE]

  1. /*
  2.  * tclMacAlloc.c --
  3.  *
  4.  *    This is a very fast storage allocator.  It allocates blocks of a
  5.  *    small number of different sizes, and keeps free lists of each size.
  6.  *    Blocks that don't exactly fit are passed up to the next larger size.
  7.  *    Blocks over a certain size are directly allocated by calling NewPtr.
  8.  *
  9.  * Copyright (c) 1983 Regents of the University of California.
  10.  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
  11.  *
  12.  * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson
  13.  *.
  14.  * See the file "license.terms" for information on usage and redistribution
  15.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  16.  *
  17.  * SCCS: @(#) tclMacAlloc.c 1.13 97/07/24 14:42:19
  18.  */
  19.  
  20. #include "tclMacInt.h"
  21. #include "tclInt.h"
  22. #include <Memory.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. /*
  27.  * Flags that are used by ConfigureMemory to define how the allocator
  28.  * should work.  They can be or'd together.
  29.  */
  30. #define MEMORY_ALL_SYS 1    /* All memory should come from the system
  31. heap. */
  32.  
  33. /*
  34.  * Amount of space to leave in the application heap for the Toolbox to work.
  35.  */
  36.  
  37. #define TOOLBOX_SPACE (32 * 1024)
  38.  
  39. static int memoryFlags = 0;
  40. static Handle toolGuardHandle = NULL;
  41.                 /* This handle must be around so that we don't
  42.                  * have NewGWorld failures. This handle is
  43.                  * purgeable. Before we allocate any blocks,
  44.                  * we see if this handle is still around.
  45.                  * If it is not, then we try to get it again.
  46.                  * If we can get it, we lock it and try
  47.                  * to do the normal allocation, unlocking on
  48.                  * the way out. If we can't, we go to the
  49.                  * system heap directly. */
  50.  
  51.  
  52. /*
  53.  * The following typedef and variable are used to keep track of memory
  54.  * blocks that are allocated directly from the System Heap.  These chunks
  55.  * of memory must always be freed - even if we crash.
  56.  */
  57.  
  58. typedef struct listEl {
  59.     Handle        memoryHandle;
  60.     struct listEl *    next;
  61. } ListEl;
  62.  
  63. ListEl * systemMemory = NULL;
  64. ListEl * appMemory = NULL;
  65.  
  66. /*
  67.  * Prototypes for functions used only in this file.
  68.  */
  69.  
  70. static pascal void    CleanUpExitProc _ANSI_ARGS_((void));
  71. void             ConfigureMemory _ANSI_ARGS_((int flags));
  72. void            FreeAllMemory _ANSI_ARGS_((void));
  73.  
  74. /*
  75.  *----------------------------------------------------------------------
  76.  *
  77.  * TclpSysRealloc --
  78.  *
  79.  *    This function reallocates a chunk of system memory.  If the
  80.  *    chunk is already big enough to hold the new block, then no
  81.  *    allocation happens.
  82.  *
  83.  * Results:
  84.  *    Returns a pointer to the newly allocated block.
  85.  *
  86.  * Side effects:
  87.  *    May copy the contents of the original block to the new block
  88.  *    and deallocate the original block.
  89.  *
  90.  *----------------------------------------------------------------------
  91.  */
  92.  
  93. VOID *
  94. TclpSysRealloc(
  95.     VOID *oldPtr,        /* Original block */
  96.     unsigned int size)        /* New size of block. */
  97. {
  98.     Handle hand;
  99.     void *newPtr;
  100.     int maxsize;
  101.  
  102.     hand = * (Handle *) ((Ptr) oldPtr - sizeof(Handle));
  103.     maxsize = GetHandleSize(hand) - sizeof(Handle);
  104.     if (maxsize < size) {
  105.     newPtr = TclpSysAlloc(size, 1);
  106.     memcpy(newPtr, oldPtr, maxsize);
  107.     TclpSysFree(oldPtr);
  108.     } else {
  109.     newPtr = oldPtr;
  110.     }
  111.     return newPtr;
  112. }
  113.  
  114. /*
  115.  *----------------------------------------------------------------------
  116.  *
  117.  * TclpSysAlloc --
  118.  *
  119.  *    Allocate a new block of memory free from the System.
  120.  *
  121.  * Results:
  122.  *    Returns a pointer to a new block of memory.
  123.  *
  124.  * Side effects:
  125.  *    May obtain memory from app or sys space.  Info is added to
  126.  *    overhead lists etc.
  127.  *
  128.  *----------------------------------------------------------------------
  129.  */
  130.  
  131. VOID *
  132. TclpSysAlloc(
  133.     long size,        /* Size of block to allocate. */
  134.     int isBin)        /* Is this a bin allocation? */
  135. {
  136.     Handle hand = NULL;
  137.     ListEl * newMemoryRecord;
  138.  
  139.     if (!(memoryFlags & MEMORY_ALL_SYS)) {
  140.  
  141.         /*
  142.          * If the guard handle has been purged, throw it away and try
  143.          * to allocate it again.
  144.          */
  145.  
  146.         if ((toolGuardHandle != NULL) && (*toolGuardHandle == NULL)) {
  147.             DisposeHandle(toolGuardHandle);
  148.             toolGuardHandle = NULL;
  149.         }
  150.  
  151.         /*
  152.          * If we have never allocated the guard handle, or it was purged
  153.          * and thrown away, then try to allocate it again.
  154.          */
  155.  
  156.         if (toolGuardHandle == NULL) {
  157.             toolGuardHandle = NewHandle(TOOLBOX_SPACE);
  158.             if (toolGuardHandle != NULL) {
  159.                 HPurge(toolGuardHandle);
  160.             }
  161.         }
  162.  
  163.     /*
  164.      * If we got the handle, lock it and do our allocation.
  165.      */
  166.  
  167.         if (toolGuardHandle != NULL) {
  168.             HLock(toolGuardHandle);
  169.         hand = NewHandle(size + sizeof(Handle));
  170.         HUnlock(toolGuardHandle);
  171.     }
  172.     }
  173.     if (hand != NULL) {
  174.     newMemoryRecord = (ListEl *) NewPtr(sizeof(ListEl));
  175.     if (newMemoryRecord == NULL) {
  176.         DisposeHandle(hand);
  177.         return NULL;
  178.     }
  179.     newMemoryRecord->memoryHandle = hand;
  180.     newMemoryRecord->next = appMemory;
  181.     appMemory = newMemoryRecord;
  182.     } else {
  183.     /*
  184.      * Ran out of memory in application space.  Lets try to get
  185.      * more memory from system.  Otherwise, we return NULL to
  186.      * denote failure.
  187.      */
  188.     isBin = 0;
  189.     hand = NewHandleSys(size + sizeof(Handle));
  190.     if (hand == NULL) {
  191.         return NULL;
  192.     }
  193.     if (systemMemory == NULL) {
  194.         /*
  195.          * This is the first time we've attempted to allocate memory
  196.          * directly from the system heap.  We need to now install the
  197.          * exit handle to ensure the memory is cleaned up.
  198.          */
  199.         TclMacInstallExitToShellPatch(CleanUpExitProc);
  200.     }
  201.     newMemoryRecord = (ListEl *) NewPtrSys(sizeof(ListEl));
  202.     if (newMemoryRecord == NULL) {
  203.         DisposeHandle(hand);
  204.         return NULL;
  205.     }
  206.     newMemoryRecord->memoryHandle = hand;
  207.     newMemoryRecord->next = systemMemory;
  208.     systemMemory = newMemoryRecord;
  209.     }
  210.     if (isBin) {
  211.     HLockHi(hand);
  212.     } else {
  213.     HLock(hand);
  214.     }
  215.     (** (Handle **) hand) = hand;
  216.  
  217.     return (*hand + sizeof(Handle));
  218. }
  219.  
  220. /*
  221.  *----------------------------------------------------------------------
  222.  *
  223.  * TclpSysFree --
  224.  *
  225.  *    Free memory that we allocated back to the system.
  226.  *
  227.  * Results:
  228.  *    None.
  229.  *
  230.  * Side effects:
  231.  *    Memory is freed.
  232.  *
  233.  *----------------------------------------------------------------------
  234.  */
  235.  
  236. void
  237. TclpSysFree(
  238.     void * ptr)        /* Free this system memory. */
  239. {
  240.     Handle hand;
  241.     OSErr err;
  242.  
  243.     hand = * (Handle *) ((Ptr) ptr - sizeof(Handle));
  244.     DisposeHandle(hand);
  245.     err = MemError();
  246. }
  247.  
  248. /*
  249.  *----------------------------------------------------------------------
  250.  *
  251.  * CleanUpExitProc --
  252.  *
  253.  *    This procedure is invoked as an exit handler when ExitToShell
  254.  *    is called.  It removes any memory that was allocated directly
  255.  *    from the system heap.  This must be called when the application
  256.  *    quits or the memory will never be freed.
  257.  *
  258.  * Results:
  259.  *    None.
  260.  *
  261.  * Side effects:
  262.  *    May free memory in the system heap.
  263.  *
  264.  *----------------------------------------------------------------------
  265.  */
  266.  
  267. static pascal void
  268. CleanUpExitProc()
  269. {
  270.     ListEl * memRecord;
  271.  
  272.     while (systemMemory != NULL) {
  273.     memRecord = systemMemory;
  274.     systemMemory = memRecord->next;
  275.     DisposeHandle(memRecord->memoryHandle);
  276.     DisposePtr((void *) memRecord);
  277.     }
  278. }
  279.  
  280. /*
  281.  *----------------------------------------------------------------------
  282.  *
  283.  * FreeAllMemory --
  284.  *
  285.  *    This procedure frees all memory blocks allocated by the memory
  286.  *    sub-system.  Make sure you don't have any code that references
  287.  *    any malloced data!
  288.  *
  289.  * Results:
  290.  *    None.
  291.  *
  292.  * Side effects:
  293.  *    Frees all memory allocated by TclpAlloc.
  294.  *
  295.  *----------------------------------------------------------------------
  296.  */
  297.  
  298. void
  299. FreeAllMemory()
  300. {
  301.     ListEl * memRecord;
  302.  
  303.     while (systemMemory != NULL) {
  304.     memRecord = systemMemory;
  305.     systemMemory = memRecord->next;
  306.     DisposeHandle(memRecord->memoryHandle);
  307.     DisposePtr((void *) memRecord);
  308.     }
  309.     while (appMemory != NULL) {
  310.     memRecord = appMemory;
  311.     appMemory = memRecord->next;
  312.     DisposeHandle(memRecord->memoryHandle);
  313.     DisposePtr((void *) memRecord);
  314.     }
  315. }
  316.  
  317. /*
  318.  *----------------------------------------------------------------------
  319.  *
  320.  * ConfigureMemory --
  321.  *
  322.  *    This procedure sets certain flags in this file that control
  323.  *    how memory is allocated and managed.  This call must be made
  324.  *    before any call to TclpAlloc is made.
  325.  *
  326.  * Results:
  327.  *    None.
  328.  *
  329.  * Side effects:
  330.  *    Certain state will be changed.
  331.  *
  332.  *----------------------------------------------------------------------
  333.  */
  334.  
  335. void
  336. ConfigureMemory(
  337.     int flags)        /* Flags that control memory alloc scheme. */
  338. {
  339.     memoryFlags = flags;
  340. }
  341.